package com.zqs.grainmall;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

/**
*  1.整合mybatis plus
 *      1.1: 导入依赖
 *        <!-- mybatis-plus-->
 *         <dependency>
 *             <groupId>com.baomidou</groupId>
 *             <artifactId>mybatis-plus-boot-starter</artifactId>
 *             <version>3.2.0</version>
 *         </dependency>
 *      1.2: 配置
 *        1.2.1: 配置数据源
 *               1.2.1.1: 导入数据库驱动。
 *               1.2.1.2: 在application.yml配置数据源相关信息
 *        1.2.2: 配置Mybatis-plus;
 *               1.2.2.1: 使用@MapperScan("xxx")扫描dao接口的位置
 *               1.2.2.2: 告诉mybatis-plus sql映射文件的位置
 *
 *
 *  2.mybatis-plus的逻辑删除
 *       2.1: 配置全局的逻辑删除规则(可以省略)
 *       2.2: 加上逻辑删除注解
 *
 *
 *  3.JSR303数据校验
 *       3.1: 给bean添加校验注解: javax.validation.constraints
 *       3.2: 给对应controller添加@Vaild来开启校验功能
 *        这里要注意，我现在用的boot版本是2.3.4，所以需要手动在maven添加spring-boot-starter-validation
 *       3.3: 给校验的bean后面紧跟一个BindingResult，就可以获取到校验结果
 *       高级用法:
 *       3.4: 分组校验功能(可以完成多场景的复杂校验)
 *         3.4.1: @NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
 *         给校验注解标注什么情况需要进行校验
 *         3.4.2: 给对应controller添加@Validated({AddGroup.class})
 *         3.4.3: 默认没有指定分组的校验注解,在分组校验情况下不生效，当我的@Validated()不指定哪个组的时候才会生效
 *
 *       3.5: 自定义校验
 *         3.5.1: 编写一个自定义的校验注解
 *         3.5.2: 编写一个自定义的校验器
 *         3.5.3: 关联自定义的校验器和自定义校验注解
 *           @Documented
 *           @Constraint(validatedBy = {ListValueConstraintValidator.class 可以指定多个不同的校验器
 *           ，适配不同类型的校验,来匹配不同的类型，这里我们演示的是Integer})
 *           @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
 *           @Retention(RUNTIME)
 *
 *  4.统一异常处理
 *       4.1: 使用@ControllerAdvice写在类上  统一处理异常
 *       4.2: 使用@ExceptionHandler写在方法上 可以处理的异常
 *
 *  5、模版引擎
 *       5.1: thymeleaf-starter :  关闭缓存
 *       5.2: 静态资源都放在static文件夹下就可以按照路径直接访问--->这里可能会出现静态image,css等资源无法加载的问题，具体看我的MyThymeleafConfig配置类
 *       5.3: 页面放在templates下，直接访问--->因为Springboot访问项目的时候，默认会访问index.html
 *       5.4: 页面不重启的情况下进行实时刷新
 *        5.4.1: 引入dev-tools或者安装JRebel插件
 *        5.4.2: 一定要先关闭缓存，不然无法实时刷新
 *
 *  6.整合redis
 *       6.1: 引入data-redis-starter
 *       6.2: 简单配置redis的host等信息
 *       6.3: 使用Springboot自动配置好的StringRedisTemplate来操作redis
 *            存数据redis-->map;存放数据key,数据值value
 *
 *  7.整合redisson作为分布式锁等功能框架
 *       7.1: 引入依赖(这里模拟的是原生jar包redisson,不是已经整合好的Springboot-start-redisson)
 *       7.2: 配置redisson
 *
 *  8.整合SpringCache简化缓存开发(redis)
 *       8.1: 引入依赖,spring-boot-starter-cache,spring-boot-starter-data-redis
 *       8.2: 写配置
 *        8.2.1: 自动配置了哪些
 *               CacheAutoConfiguration 会导入 RedisCacheConfiguration;
 *               自动配置好了缓存管理器 RedisCacheManager
 *        8.2.2: 在properties里配置redis作为缓存
 *       8.3: 测试使用缓存:主要使用以下注解
 *
 * @Cacheable: Triggers cache population. 触发将数据保存到缓存的操作
 *
 * @CacheEvict: Triggers cache eviction.  触发将数据从缓存中删除的操作
 *
 * @CachePut: Updates the cache without interfering with the method execution.  不影响方法执行更新缓存
 *
 * @Caching: Regroups multiple cache operations to be applied on a method.   组合多个缓存操作
 *
 * @CacheConfig: Shares some common cache-related settings at class-level.   在类级别共享缓存的相同配置
 *       8.4: 开启缓存功能@EnableCaching
 *       8.5: 只需要使用注解就能完成缓存操作
 *
 *  9.Spring-Cache的不足:
 *       9.1: 读模式:
 *         9.1.1: 缓存穿透: 查询一个null数据，解决:缓存空数据，可以在配置文件中设置
 *         9.1.2: 缓存击穿: 大量并发过来同时查询一个正好过期的数据。 解决: 加锁: ?默认是无加锁的,在@Cacheable注解里面加上 sync = true 解决击穿
 *         9.1.3: 缓存雪崩: 大量的key同时过期。 解决: 加过期时间  spring.cache.redis.time-to-live
 *       9.2: 写模式:（缓存与数据库一致）
 *         9.2.1: 读写加锁
 *         9.2.2: 引入Canal,感知Mysql的更新去更新数据库
 *         9.3.3: 读多写多，直接去数据库查询就行
 *   原理:
 *      CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写
 *
 *   总结:
 *   常规数据(读多写少，即时性，一致性要求不高的数据)；完全可以使用Spring-Cache，写模式只要缓存有过期时间就足够了
 *
 *   特殊数据:特殊设计
 *
 *
 *
* */
@EnableRedisHttpSession
@EnableFeignClients(basePackages = "com.zqs.grainmall.product.feign")
@MapperScan("com.zqs.grainmall.product.dao")
@SpringBootApplication
@EnableDiscoveryClient
public class GrainmallProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(GrainmallProductApplication.class, args);
    }

}
